package xin.nick.system.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import xin.nick.common.core.util.BeanCopierUtil;
import xin.nick.system.domain.vo.SystemAuthorityVO;
import xin.nick.system.entity.SystemAuthority;
import xin.nick.system.entity.SystemRoleAuthority;
import xin.nick.system.mapper.SystemAuthorityMapper;
import xin.nick.system.mapper.SystemRoleAuthorityMapper;
import xin.nick.system.mapper.SystemUserRoleMapper;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Nick
 * @date 2022/10/30
 */
@Component
@RequiredArgsConstructor
public class SystemAuthorityManager {

    private final SystemAuthorityMapper systemAuthorityMapper;
    private final SystemRoleAuthorityMapper systemRoleAuthorityMapper;
    private final SystemUserRoleMapper systemUserRoleMapper;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 获取权限列表
     *
     * @return List<Authority>
     */
    public List<SystemAuthority> getSystemAuthorityList() {
        return systemAuthorityMapper.selectList(Wrappers.emptyWrapper());
    }


    /**
     * 获取权限map
     *
     * @return Map<Long, Authority>
     */
    public Map<Long, SystemAuthority> getSystemAuthorityMap() {
        List<SystemAuthority> systemAuthorityList = getSystemAuthorityList();

        return systemAuthorityList.stream()
                .filter(Objects::nonNull)
                .filter(authority -> Objects.nonNull(authority.getAuthorityId()))
                .collect(Collectors.toMap(SystemAuthority::getAuthorityId, Function.identity(), (v1, v2) -> v2));
    }


    /**
     * 获取所有权限的id列表
     *
     * @return
     */
    public List<Long> getSystemAuthorityIdList() {
        List<SystemAuthority> systemAuthorityList = getSystemAuthorityList();
        return systemAuthorityList.stream()
                .filter(Objects::nonNull)
                .map(SystemAuthority::getAuthorityId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }


    /**
     * 获取存在的权限id,存在的才返回
     *
     * @param filterAuthorityIdList
     * @return
     */
    public List<Long> checkAndGetExistIdList(List<Long> filterAuthorityIdList) {
        if (CollectionUtils.isEmpty(filterAuthorityIdList)) {
            return new ArrayList<>();
        }
        List<Long> authorityIdList = getSystemAuthorityIdList();
        return filterAuthorityIdList.stream()
                .filter(Objects::nonNull)
                .filter(authorityIdList::contains)
                .collect(Collectors.toList());
    }

    /**
     * 根据角色id获取权限列表
     *
     * @param roleId
     * @return
     */
    public List<SystemAuthority> getAuthorityListByRoleId(Long roleId) {

        if (Objects.isNull(roleId)) {
            return new ArrayList<>();
        }

        // 根据获取角色权限管理关系
        List<SystemRoleAuthority> roleAuthorityList = systemRoleAuthorityMapper.selectList(
                Wrappers.<SystemRoleAuthority>lambdaQuery()
                        .eq(SystemRoleAuthority::getRoleId, roleId));
        if (CollectionUtils.isEmpty(roleAuthorityList)) {
            return new ArrayList<>();
        }

        // 根据关联关系获取到权限id列表
        List<Long> authorityIdList = roleAuthorityList.stream()
                .filter(Objects::nonNull).map(SystemRoleAuthority::getAuthorityId).filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(authorityIdList)) {
            return new ArrayList<>();
        }

        // 查询权限id关联的权限列表
        return systemAuthorityMapper.selectList(
                Wrappers.<SystemAuthority>lambdaQuery()
                        .in(SystemAuthority::getAuthorityId, authorityIdList)
        );
    }

    /**
     * 根据角色id获取权限id列表
     *
     * @param roleId
     * @return
     */
    public List<Long> getAuthorityIdListByRoleId(Long roleId) {

        if (Objects.isNull(roleId)) {
            return new ArrayList<>();
        }

        return getAuthorityListByRoleId(roleId).stream()
                .filter(Objects::nonNull)
                .map(SystemAuthority::getAuthorityId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 更新角色和权限列表关联
     *
     * @param roleId
     * @param authorityIdList
     */
    public void updateRoleAuthorityList(Long roleId, List<Long> authorityIdList) {
        if (CollectionUtils.isEmpty(authorityIdList)) {
            authorityIdList = new ArrayList<>();
        }
        authorityIdList = authorityIdList.stream().filter(Objects::nonNull).collect(Collectors.toList());
        Assert.notNull(roleId, "角色id为空");

        // 删除原来的权限关联
        systemRoleAuthorityMapper.delete(Wrappers.<SystemRoleAuthority>lambdaQuery().eq(SystemRoleAuthority::getRoleId, roleId));
        // 插入新的角色关联
        for (Long authorityId : authorityIdList) {
            SystemRoleAuthority roleAuthority = new SystemRoleAuthority();
            roleAuthority.setRoleId(roleId);
            roleAuthority.setAuthorityId(authorityId);
            systemRoleAuthorityMapper.insert(roleAuthority);
        }
    }

    /**
     * 根据角色id列表获取AuthorityList
     * @param roleIdList
     * @return
     */
    public List<SystemAuthority> getAuthorityListByRoleIdList(List<Long> roleIdList) {

        if (CollUtil.isEmpty(roleIdList)) {
            return new ArrayList<>();
        }

        // 获取角色id和权限id关联列表
        List<SystemRoleAuthority> roleAuthorityList = systemRoleAuthorityMapper.selectList(
                Wrappers.<SystemRoleAuthority>lambdaQuery()
                        .in(SystemRoleAuthority::getRoleId, roleIdList));
        if (CollUtil.isEmpty(roleAuthorityList)) {
            return new ArrayList<>();
        }

        // 权限id列表
        List<Long> authorityIdList = roleAuthorityList.stream()
                .filter(Objects::nonNull)
                .map(SystemRoleAuthority::getAuthorityId)
                .filter(Objects::nonNull).collect(Collectors.toList());
        if (CollUtil.isEmpty(authorityIdList)) {
            return new ArrayList<>();
        }

        // 获取到权限列表
        List<SystemAuthority> authorityList = systemAuthorityMapper.selectList(
                        Wrappers.<SystemAuthority>lambdaQuery()
                                .in(SystemAuthority::getAuthorityId, authorityIdList))
                .stream().filter(Objects::nonNull).collect(Collectors.toList());
        ;
        return authorityList;
    }

    /**
     * 构建 权限树形结构列表
     * @param authorityList
     * @return
     */
    public List<SystemAuthorityVO> buildTreeList(List<SystemAuthority> authorityList) {

        List<SystemAuthorityVO> resultList = new ArrayList<>();
        if (CollUtil.isEmpty(authorityList)) {
            return resultList;
        }


        List<SystemAuthorityVO> authorityVoList = BeanCopierUtil.copyToList(authorityList, SystemAuthorityVO.class);

        Map<Long, SystemAuthorityVO> authorityVoMap = authorityVoList.stream()
                .filter(Objects::nonNull)
                .filter(authorityVO -> Objects.nonNull(authorityVO.getAuthorityId()))
                .collect(Collectors.toMap(SystemAuthorityVO::getAuthorityId, Function.identity(), (v1, v2) -> v2));

        // 遍历所有的菜单,将子级分类关联上父级
        for (Map.Entry<Long, SystemAuthorityVO> authorityVOEntry : authorityVoMap.entrySet()) {
            SystemAuthorityVO authorityVO = authorityVOEntry.getValue();
            // 获取父级
            Long parentId = authorityVO.getParentId();
            SystemAuthorityVO parent = authorityVoMap.get(parentId);
            if (Objects.isNull(parent)) {
                continue;
            }

            // 将当前对象加入父级的children
            List<SystemAuthorityVO> children = parent.getChildren();
            if (Objects.isNull(children)) {
                children = new ArrayList<>();
            }
            children.add(authorityVO);
            parent.setChildren(children);

        }


        // 获取父级为0的权限菜单,返回
        resultList = authorityVoMap.values().stream()
                .filter(authorityVO -> Objects.equals(0L, authorityVO.getParentId()))
                .collect(Collectors.toList());

        return resultList;

    }


    /**
     * 获取所有的子级id
     * @param authorityId
     */
    public List<Long> getAllChildrenIdList(Long authorityId) {

        List<SystemAuthority> authorityList = getSystemAuthorityList();
        Map<Long, List<SystemAuthority>> parentIdAuthorityMap = authorityList.stream()
                .filter(Objects::nonNull)
                .filter(authority -> Objects.nonNull(authority.getParentId()))
                .collect(Collectors.groupingBy(SystemAuthority::getParentId));
        List<Long> authorityIdList = new ArrayList<Long>();
        findAllChildrenIdList(authorityIdList, parentIdAuthorityMap, authorityId);
        return authorityIdList;
    }

    /**
     * 获取所有的子类id列表
     * @param authorityIdList
     * @param parentIdAuthorityMap
     * @param authorityId
     */
    public void findAllChildrenIdList(List<Long> authorityIdList, Map<Long, List<SystemAuthority>> parentIdAuthorityMap, Long authorityId) {
        List<SystemAuthority> authorityList = parentIdAuthorityMap.get(authorityId);
        if (CollUtil.isEmpty(authorityList)) {
            return;
        }
        for (SystemAuthority authority : authorityList) {
            Long childId = authority.getAuthorityId();
            if (authorityIdList.contains(childId)) {
                continue;
            }
            authorityIdList.add(childId);
            findAllChildrenIdList(authorityIdList, parentIdAuthorityMap, authority.getAuthorityId());
        }
    }

    /**
     * 根据request获取需要的权限key
     * @param request
     * @return
     */
    public String getAuthorityKeyByRequest(HttpServletRequest request) {

        List<SystemAuthority> systemAuthorityList = getSystemAuthorityList();
        String requestUri = request.getRequestURI();
        for (SystemAuthority systemAuthority : systemAuthorityList) {
            String authorityKey = systemAuthority.getAuthorityKey();
            String authorityPath = systemAuthority.getAuthorityPath();
            if (CharSequenceUtil.isBlank(authorityKey) || CharSequenceUtil.isBlank(authorityPath)) {
                continue;
            }
            if (antPathMatcher.match(authorityPath, requestUri)) {
                return authorityKey;
            }
        }


//        Map<AntPathRequestMatcher, String> pathAuthorityKeyMap = getPathAuthorityKeyMap();
//        for (Map.Entry<AntPathRequestMatcher, String> antPathRequestMatcherStringEntry : pathAuthorityKeyMap.entrySet()) {
//            AntPathRequestMatcher keyMatcher = antPathRequestMatcherStringEntry.getKey();
//            String value = antPathRequestMatcherStringEntry.getValue();
//
//            if(keyMatcher.matches(request)) {
//                return value;
//            }
//        }
//
        return "";
    }

    /**
     * 获取请求pathMatcher和权限key的map
     * 不太好用,耗时间耗内存,
     * @return
     */
    public Map<AntPathRequestMatcher, String> getPathAuthorityKeyMap() {

        Map<AntPathRequestMatcher, String> map = new HashMap<>();

        List<SystemAuthority> systemAuthorityList = getSystemAuthorityList();

        for (SystemAuthority systemAuthority : systemAuthorityList) {
            String authorityKey = systemAuthority.getAuthorityKey();
            String authorityPath = systemAuthority.getAuthorityPath();
            if (CharSequenceUtil.isBlank(authorityKey) || CharSequenceUtil.isBlank(authorityPath)) {
                continue;
            }

            map.put(new AntPathRequestMatcher(authorityPath), authorityKey);
        }

        return map;

    }
}
